package co.com.umobile.service;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HTTP;
import org.json.JSONObject;

import android.content.Context;
import co.com.umobile.R;
import co.com.umobile.application.GlobalState;
import co.com.umobile.common.Numbers;
import co.com.umobile.common.ResponseCodes;
import co.com.umobile.domain.ServiceResponse;
import co.com.umobile.domain.User;
import co.com.umobile.network.SSLSocketFactory;
import co.com.umobile.network.URLServiceConnection;

/**
 * <p>
 * Class used to handle the authentication web service
 * </p>
 * <p>
 * PSL Productora de Software S.A.<BR>
 * Created on: 14/06/2011.<BR>
 * 
 * @author Sergio Granada.
 *         </p>
 */
public class LoginExtService {

	/**
	 * handles the login authentication.
	 * @param jsonObject jsonObject.
	 * @param userCode username.
	 * @param password password.
	 * @param globalState global state.
	 * @param context context.
	 * @return ServiceResponse.
	 * @throws Exception .
	 */
	public ServiceResponse authenticate(JSONObject jsonObject, String userCode, String password, GlobalState globalState, Context context)
			throws Exception {
		
	SchemeRegistry schemeRegistry = new SchemeRegistry();
		 
        /*
     * // http scheme
     * schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
     */
    // https scheme
    schemeRegistry.register(new Scheme("https", new SSLSocketFactory(),  		
        Integer.valueOf((((GlobalState) context.getApplicationContext()).getPort()).toString())));

		HttpParams httpParameters = new BasicHttpParams();
//		HttpConnectionParams.setConnectionTimeout(httpParameters, Numbers.TEN_THOUSAND);
//		HttpConnectionParams.setSoTimeout(httpParameters, Numbers.FIFTEEN_THOUSAND);
		
		HttpConnectionParams.setConnectionTimeout(httpParameters, 80000);
		HttpConnectionParams.setSoTimeout(httpParameters, 100000);
		
		ThreadSafeClientConnManager clientConnectionManager = new ThreadSafeClientConnManager(httpParameters, schemeRegistry);
		
		HttpClient httpclient = new DefaultHttpClient(clientConnectionManager, httpParameters);
		 
		// HttpPost request = new HttpPost("http://10.0.2.2:9090/SyncAsesorServer/rest/auth");
    HttpPost request = new HttpPost(URLServiceConnection.getURLService(context, URLServiceConnection.LOGIN_URL) + "/"
        + String.valueOf(globalState.getVersionCode()));
		request.setHeader("Accept", "text/plain");
		request.setHeader("Accept-Charset", "utf-8");

		request.addHeader("Content-Type", "application/octet-stream");
		request.addHeader("Accept-Encoding", "gzip");
		request.addHeader("Connection", "Keep-Alive");
		HttpResponse response = null;

		ByteArrayEntity se = new ByteArrayEntity(compress(jsonObject.toString()));
		se.setContentEncoding(new BasicHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_KEEP_ALIVE));

		request.setEntity(se);

		response = httpclient.execute(request);

		if (response.getStatusLine().getStatusCode() != Numbers.TWO_HUNDRED) {
			return getServiceError(context, response);
		}

		String data = null;

		InputStream instream = response.getEntity().getContent();
		Header contentEncoding = response.getFirstHeader("Content-Encoding");
    if (contentEncoding != null && "gzip".equalsIgnoreCase(contentEncoding.getValue())) {
			instream = new GZIPInputStream(instream);

			InputStreamReader reader = new InputStreamReader(instream);
			BufferedReader in = new BufferedReader(reader);

			String readed = "";
			while ((readed = in.readLine()) != null) {
				data = readed;
			}

		}

		if (data == null) {
			return getServiceError(context, response);
		}

		JSONObject jsonResponse = new JSONObject(data);

		User userSession = new User();
		userSession.setUserCode(userCode);
		userSession.setPassword(password);
		userSession.setName(jsonResponse.optString("na", null));
		userSession.setSessionId(jsonResponse.optString("sid", null));
		userSession.setUserType(jsonResponse.optInt("ut", 0));
		userSession.setUserTypeDescription(jsonResponse.optString("utd", null));


		ServiceResponse serviceResponse = new ServiceResponse();
		serviceResponse.setCode(jsonResponse.optString("crt", ResponseCodes.SUCCESSFUL));
		serviceResponse.setDescription(jsonResponse.optString("drt", ""));
		serviceResponse.setUserSession(userSession);
		return serviceResponse;
	}

	/**
	 * used for connection errors.
	 * @param context context application.
	 * @param response service response.
	 * @return ServiceResponse.
	 */
	private ServiceResponse getServiceError(Context context, HttpResponse response) {

		ServiceResponse serviceResponse = null;
		String responseCode = null;
		String responseMessage = null;

		if (response != null && response.getStatusLine() != null && response.getStatusLine().getStatusCode() == ResponseCodes.CUSTOM_ERROR) {

			responseCode = response.getFirstHeader(ResponseCodes.ERROR_CODE).getValue();
			responseMessage = response.getFirstHeader(ResponseCodes.ERROR_MESSAGE).getValue();

		} else {
			responseCode = ResponseCodes.UNKNOWN_ERROR;
			responseMessage = context.getResources().getString(R.string.login_authentication_error);
		}

		serviceResponse = new ServiceResponse();
		serviceResponse.setCode(responseCode);
		serviceResponse.setDescription(responseMessage);

		return serviceResponse;
	}

	/**
	 * Compress the data using GZIP.
	 * 
	 * @param string string to gzip.
	 * @return array of bytes.
	 * @throws IOException .
	 */
	public static byte[] compress(String string) throws IOException {
		ByteArrayOutputStream os = new ByteArrayOutputStream(string.length());
		GZIPOutputStream gos = new GZIPOutputStream(os);
		gos.write(string.getBytes());
		gos.close();
		byte[] compressed = os.toByteArray();
		os.close();
		return compressed;
	}

}
